#ifndef RP2SHADEREFFECT_H
#define RP2SHADEREFFECT_H

#include "Rp2Effect.h"
#include "Rp2VertexShader.h"
#include "Rp2PixelShader.h"

namespace Rp2
{

class Renderer;

class ShaderEffect : public Effect
{
	RP2_DECLARE_RTTI;
	RP2_DECLARE_NAME_ID;

public:
	ShaderEffect(int iPassQuantity);
	virtual ~ShaderEffect();
	
    // The shader effect is a manager of the vertex and pixel shaders.  It
    // reimplements the user-relevant interfaces for the managed objects as a
    // convenience to avoid long expressions involving pointer dereferencing.

    // The number of vertex/pixel shader pairs.  The Set* call reallocates the
    // vertex shader, pixel shader, and alpha state arrays.
    void SetPassQuantity (int iPassQuantity);
    int GetPassQuantity () const;

    // Set any global state needed by the pass and restore it later.  The
    // base class enables and disables blending as needed for multipass
    // and multieffect drawing.
	virtual void SetGlobalState(int iPass, Renderer* pkRenderer,
		bool bPrimaryEffect);
	virtual void RestoreGlobalState(int iPass, Renderer* pkRenderer,
		bool bPrimaryEffect);

    // Allow derived classes to set the data sources in the UserConstant
    // objects that correspond to shader programs.
    void ConnectVShaderConstant (int iPass, const std::string& rkName,
        float* pfSource);
    void ConnectPShaderConstant (int iPass, const std::string& rkName,
        float* pfSource);
    void ConnectVShaderConstants (int iPass);
    void ConnectPShaderConstants (int iPass);

    // Vertex shader interfaces.
    bool SetVShader (int iPass, VertexShader* pkVShader);
    VertexShader* GetVShader (int iPass);
    VertexProgram* GetVProgram (int iPass);
    const std::string& GetVShaderName (int iPass) const;
    int GetVConstantQuantity (int iPass) const;
    UserConstant* GetVConstant (int iPass, int i);
    UserConstant* GetVConstant (int iPass, const std::string& rkName);
    int GetVTextureQuantity (int iPass) const;
    Texture* GetVTexture (int iPass, int i);
    Texture* GetVTexture (int iPass, const std::string& rkName);
    bool SetVTexture (int iPass, int i, Texture* pkTexture);
    bool SetVTexture (int iPass, int i, const std::string& rkName);

    // Pixel shader interfaces.
    bool SetPShader (int iPass, PixelShader* pkPShader);
    PixelShader* GetPShader (int iPass);
    PixelProgram* GetPProgram (int iPass);
    const std::string& GetPShaderName (int iPass) const;
    int GetPConstantQuantity (int iPass) const;
    UserConstant* GetPConstant (int iPass, int i);
    UserConstant* GetPConstant (int iPass, const std::string& rkName);
    int GetPTextureQuantity (int iPass) const;
    Texture* GetPTexture (int iPass, int i);
    Texture* GetPTexture (int iPass, const std::string& rkName);
    bool SetPTexture (int iPass, int i, Texture* pkTexture);
    bool SetPTexture (int iPass, int i, const std::string& rkName);

    // The functions are called by Renderer::LoadResources and
    // Renderer::ReleaseResources for Geometry and Effect objects.  The
    // resources are transferred from system memory to video memory.
    virtual void LoadResources (Renderer* pkRenderer, Geometry* pkGeometry);
    virtual void ReleaseResources (Renderer* pkRenderer,
        Geometry* pkGeometry);

protected:
	ShaderEffect();

	void SetDefaultAlphaState();

    // When SetVShader and SetPShader are called, we must verify that the
    // outputs of the vertex program are compatible with the inputs of the
    // pixel program.  This function does so.  The first time you set the
    // shaders, there are no side effects to consider.  However, in the
    // unlikely event you want to change *both* shader programs later, call
    // SetVShader and SetPShader *first* with null inputs, and then call
    // them again with the new shaders.
    bool AreCompatible (const VertexProgram* pkVProgram,
        const PixelProgram* pkPProgram) const;

	int m_iPassQuantity;
	std::vector<VertexShaderPtr> m_kVShader;
	std::vector<PixelShaderPtr> m_kPShader;
	std::vector<AlphaStatePtr> m_kAlphaState;

	typedef std::pair<UserConstant*, float*> Connection;
	std::vector<std::vector<Connection> > m_kVConnect;
	std::vector<std::vector<Connection> > m_kPConnect;
};

typedef Pointer<ShaderEffect> ShaderEffectPtr;

#include "Rp2ShaderEffect.inl"

}

#endif